/* Copyright 2008 Bas van den Berg
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "LoginSession.h"
#include "Connection.h"
#include "Database.h"
#include "Utils.h"
#include "config.h"
#include "myassert.h"

using namespace Chronos;

LoginSession::LoginSession(Connection* con, Database& db_)
        : prompt("name: ")
        , state(NAME)
		, connection(con)
		, timeout(Config::LOGIN_TIMEOUT + 1)    // FIX
		, retries(3)
        , database(db_)
{
    connection->write("Welcome to Example Mud\n");
    printPrompt();
}


LoginSession::~LoginSession() {
    if (state != DONE) delete connection;
}


int LoginSession::handlePulse() {
    ASSERT_NOT_EQUAL(DONE, state);
    if (timeout == 0) {
		connection->write("(timeout)\n");
		return FAIL;
	}
    --timeout;

    int size = connection->read(readBuffer, MAX_INPUT_LENGTH);
    if (size == Connection::ERROR) return FAIL;
    if (size == Connection::NODATA) return INPROGRESS;

    size = Utils::stripNewline(readBuffer);
    if (size == 0) {
        if (!canRetry()) return FAIL;
        printPrompt();
        timeout = Config::LOGIN_TIMEOUT + 1;
        return INPROGRESS;
    }

    if (readBuffer[0] == -1) return INPROGRESS;
    timeout = Config::LOGIN_TIMEOUT + 1;

    if (state == NAME) return handleName(readBuffer);
    else return handlePassword(readBuffer);
}


int LoginSession::handleName(char* buf) {
    if (strcmp("new", buf) == 0) {
        state = DONE;
        return NEW_PLAYER;
    }
    if (strcmp("quit", buf) == 0) {
        connection->write("Goodbye!\n");
        return FAIL;
    }
    if (database.hasPlayer(buf)) {
        name = buf;
        state = PASSWORD;
        retries = 3;
        setPrompt("password: ");
        printPrompt();
        connection->setEcho(false);
    } else {
        if (!canRetry()) return FAIL;
        connection->write("Unknown player. Type 'new' to create a new player.\n");
        printPrompt();
    }
    return INPROGRESS;
}


int LoginSession::handlePassword(char* buf) {
    connection->setEcho(true);
    if (database.checkPasswd(name, buf)) {
        state = DONE;
        return SUCCESS;
    }
    connection->write("password incorrect!\n");
    if (!canRetry()) return FAIL;
    printPrompt();
    connection->setEcho(false);
    return INPROGRESS;
}


bool LoginSession::canRetry() {
    --retries;
    if (retries == 0) {
		connection->write("Bye!\n");
		return false;
	}
    return true;
}


void LoginSession::setPrompt(const char* p) { prompt = p; }


void LoginSession::printPrompt() { connection->write(prompt.c_str()); }


